uniform sampler2D tex;     //Texture unit we are to use (0 by default)
uniform samplerCube refMap;
uniform float time;	   //time since program start
uniform float waterHeight; //Height of the water mest
uniform float waterWidth;  //Width of the water mesh
uniform vec3 camPos;       //Camera position
varying vec3 normal;       //The normal for this vertex
varying vec3 lightDir;     //Direction of the light
varying vec3 eyeVec;       //Direction of the line of sight
varying vec4 pos;          //Calculated vertex position

float dist(float x, float z);
float getHeight(float x, float z, float wavelength, float frequency);
vec4 getPosition(float x, float z, float wavelength, float frequency);
vec3 calcNormal(vec4 pos, float wavelength, float frequency);

void main(void) {
    pos = getPosition(gl_Vertex.x, gl_Vertex.z, 5, 2);
    normal = gl_NormalMatrix * calcNormal(pos, 5, 2);
    lightDir = gl_LightSource[0].position.xyz - pos.xyz;
    eyeVec =  -vec3(gl_ModelViewMatrix * pos);
    gl_Position = gl_ModelViewProjectionMatrix*pos;
}

//Return the distance from the top left corner of the water mesh (0, 0)
float dist(float x, float z) {
    return sqrt(x*x+z*z);
}

//Return a height ranging from {-1, 1}
float getHeight(float x, float z, float wavelength, float frequency) {
    float height = texture2D(tex, gl_MultiTexCoord0.st).r;
    height = sin((dist(x, z) + (time*frequency)) / (height*wavelength));
    return height;
}

//Get position from 2D texture map
vec4 getPosition(float x, float z, float wavelength, float frequency) {
    return vec4(x, getHeight(x, z, wavelength, frequency), z, 1);
}

//Calculate the normal for the specified position
vec3 calcNormal(vec4 pos, float wavelength, float frequency){

    vec3 left = vec3(0,0,0);
    vec3 down = vec3(0,0,0);
    vec3 right = vec3(0,0,0);
    vec3 up = vec3(0,0,0);

    vec3 cross1 = vec3(0,0,0);
    vec3 cross2 = vec3(0,0,0);
    vec3 cross3 = vec3(0,0,0);
    vec3 cross4 = vec3(0,0,0);

    //get left
    if( pos.x > 0 ){
        left = (getPosition(pos.x-1, pos.z, wavelength, frequency) - pos).xyz;
    }
    //get right
    if( pos.x < waterWidth - 2 ){
        right = (getPosition(pos.x +1, pos.z, wavelength, frequency) - pos).xyz;
    }
    //get up
    if( pos.z > 0 ){
        up = (getPosition(pos.x, pos.z-1, wavelength, frequency) - pos).xyz;
    }
    //get down
    if( pos.z < waterHeight -2 ){
        down = (getPosition(pos.x, pos.z+1, wavelength, frequency) - pos).xyz;
    }

    //Now calculate the normals
    cross1 = cross(left, down);
    cross2 = cross(down, right);
    cross3 = cross(right, up);
    cross4 = cross(up, left);

    return normalize((cross1 + cross2 + cross3 + cross4)/4);
}
